package com.example.tms.service;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.mindrot.jbcrypt.BCrypt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.tms.controller.EmployeeController;
import com.example.tms.dto.EmployeeDetailDTO;
import com.example.tms.entity.Employee;
import com.example.tms.entity.EmployeeDepartment;
import com.example.tms.mapper.EmployeeDepartmentMapper;
import com.example.tms.mapper.EmployeeMapper;

@Service
public class EmployeeService {
    private static final org.apache.logging.log4j.Logger log =
            org.apache.logging.log4j.LogManager.getLogger(EmployeeController.class);

    @Autowired
    private EmployeeMapper employeeMapper;
    
    @Autowired
    private EmployeeDepartmentMapper employeeDepartmentMapper;

    // 哈希加密截断
    private String truncateHash(String hash, int maxLength) {
        return hash.length() > maxLength ? hash.substring(0, maxLength) : hash;
    }

    // 获取所有员工列表
    public List<Employee> selectAll() {
//        log.debug("执行操作: 查询所有员工 | 时间: {}", LocalDateTime.now());
        try {
            List<Employee> employees = employeeMapper.selectList(null);
            return employees;
        } catch (Exception e) {
            throw new RuntimeException("查询失败", e);
        }
    }
    
    // 获取所有员工完整信息(包含部门信息)
    public List<EmployeeDetailDTO> getAllEmployeeDetails() {
        log.debug("执行操作: 查询所有员工完整信息 | 时间: {}", LocalDateTime.now());
        try {
            List<Employee> employees = employeeMapper.selectList(null);
            if (employees.isEmpty()) {
                return Collections.emptyList();
            }
            
            List<Integer> empIds = employees.stream()
                .map(Employee::getId)
                .collect(Collectors.toList());
                
            List<EmployeeDepartment> departments = employeeDepartmentMapper.findCurrentDepartmentsByEmployeeIds(empIds);
            Map<Integer, EmployeeDepartment> departmentMap = departments.stream()
                .collect(Collectors.toMap(EmployeeDepartment::getEmpId, Function.identity()));
                
            return employees.stream()
                .map(emp -> new EmployeeDetailDTO(emp, departmentMap.get(emp.getId())))
                .collect(Collectors.toList());
        } catch (Exception e) {
            throw new RuntimeException("查询所有员工完整信息失败", e);
        }
    }
    // 根据 ID 查询员工
    public Employee selectById(Integer id) {
        log.debug("执行操作: 查询员工详情 | 员工ID: {} | 时间: {}", id, LocalDateTime.now());
        try {
            Employee employee = employeeMapper.selectById(id);
            return employee;
        } catch (Exception e) {
            throw new RuntimeException("查询失败", e);
        }
    }
    
    // 获取员工完整信息(包含部门信息)
    public EmployeeDetailDTO getEmployeeDetail(Integer id) {
        log.debug("执行操作: 查询员工完整信息 | 员工ID: {} | 时间: {}", id, LocalDateTime.now());
        try {
            Employee employee = employeeMapper.selectById(id);
            if (employee == null) {
                return null;
            }
            
            EmployeeDepartment department = employeeDepartmentMapper.findCurrentDepartmentByEmployeeId(id);
            return new EmployeeDetailDTO(employee, department);
        } catch (Exception e) {
            throw new RuntimeException("查询员工完整信息失败", e);
        }
    }

    // 分页查询
    public IPage<Employee> selectPage(Integer pageNum, Integer pageSize) {
        log.debug("执行操作: 分页查询员工 | 页码: {}, 每页大小: {} | 时间: {}",
                pageNum, pageSize, LocalDateTime.now());
        try {
            Page<Employee> page = new Page<>(pageNum, pageSize);
            IPage<Employee> result = employeeMapper.selectPage(page, null);
            return result;
        } catch (Exception e) {
            throw new RuntimeException("分页查询失败", e);
        }
    }

    // 添加员工
    public int insert(Employee employee) {
        log.debug("执行操作: 新增员工 | 员工姓名: {} | 时间: {}",
                employee.getName(), LocalDateTime.now());
        try {
            // 密码加密处理
            String rawPassword = employee.getPassword();
            String hashedPassword = BCrypt.hashpw(rawPassword, BCrypt.gensalt());
            employee.setPassword(truncateHash(hashedPassword, 45));

            int result = employeeMapper.insert(employee);
            return result;
        } catch (Exception e) {
            throw new RuntimeException("添加失败", e);
        }
    }

    // 更新员工信息
    public int update(Employee employee) {
        log.debug("执行操作: 更新员工 | 员工ID: {} | 时间: {}",
                employee.getId(), LocalDateTime.now());
        try {
            if (employee.getPassword() != null && !employee.getPassword().isEmpty()) {
                String hashedPassword = BCrypt.hashpw(employee.getPassword(), BCrypt.gensalt());
                employee.setPassword(truncateHash(hashedPassword, 45));
            }

            int result = employeeMapper.updateById(employee);
            return result;
        } catch (Exception e) {
            throw new RuntimeException("更新失败", e);
        }
    }

    // 删除员工
    public int deleteById(Integer id) {
        log.warn("执行操作: 删除员工 | 员工ID: {} | 时间: {}", id, LocalDateTime.now());
        try {
            int result = employeeMapper.deleteById(id);
            return result;
        } catch (Exception e) {
            throw new RuntimeException("删除失败", e);
        }
    }
    
    public int createEmployeeWithDepartment(EmployeeDetailDTO dto) {
        log.debug("执行操作: 创建员工及部门信息 | 员工姓名: {} | 时间: {}", 
            dto.getName(), LocalDateTime.now());
        
        try {
            // 1. 创建员工基本信息
            Employee employee = new Employee();
            employee.setName(dto.getName());
            employee.setPassword(dto.getPassword());
            employee.setGender(dto.getGender());
            employee.setPhone(dto.getPhone());
            employee.setBirthDate(dto.getBirthDate());
            employee.setHireDate(dto.getHireDate());
            employee.setEducation(dto.getEducation());
            employee.setStatus(dto.getStatus());
            employee.setEmpType(dto.getEmpType());
            employee.setEmpPhoto(dto.getEmpPhoto());
            employee.setSchool(dto.getSchool());
            employee.setDescription(dto.getDescription());
            
            // 密码加密处理
            String hashedPassword = BCrypt.hashpw(employee.getPassword(), BCrypt.gensalt());
            employee.setPassword(truncateHash(hashedPassword, 45));
            
            int empResult = employeeMapper.insert(employee);
            if (empResult <= 0) {
                throw new RuntimeException("员工创建失败");
            }
            
            // 2. 创建部门关联信息
            EmployeeDepartment department = dto.toEmployeeDepartment();
            department.setEmpId(employee.getId()); // 设置新创建的员工ID
            
            int depResult = employeeDepartmentMapper.insert(department);
            if (depResult <= 0) {
                throw new RuntimeException("部门关联创建失败");
            }
            
            return 1; // 成功
        } catch (Exception e) {
            log.error("创建员工及部门信息失败: {}", e.getMessage());
            throw new RuntimeException("创建员工及部门信息失败: " + e.getMessage());
        }
    }

    // 更新员工及部门信息
    public int updateEmployeeWithDepartment(EmployeeDetailDTO dto) {
        log.debug("执行操作: 更新员工及部门信息 | 员工ID: {} | 时间: {}", 
            dto.getId(), LocalDateTime.now());
        
        try {
            // 更新员工基本信息
            Employee employee = new Employee();
            employee.setId(dto.getId());
            employee.setName(dto.getName());
            employee.setGender(dto.getGender());
            employee.setPhone(dto.getPhone());
            employee.setBirthDate(dto.getBirthDate());
            employee.setHireDate(dto.getHireDate());
            employee.setEducation(dto.getEducation());
            employee.setStatus(dto.getStatus());
            employee.setEmpType(dto.getEmpType());
            employee.setEmpPhoto(dto.getEmpPhoto());
            employee.setSchool(dto.getSchool());
            employee.setDescription(dto.getDescription());
            
            int empResult = employeeMapper.updateById(employee);
            if (empResult <= 0) {
                throw new RuntimeException("员工信息更新失败");
            }

            // 处理部门信息
            EmployeeDepartment currentDep = employeeDepartmentMapper.findCurrentDepartmentByEmployeeId(dto.getId());
            if (currentDep != null) {
                // 检查部门信息是否有变化
                boolean departmentChanged = !currentDep.getDepId().equals(dto.getDepId()) ||
                                           !currentDep.getPosition().equals(dto.getPosition()) ||
                                           !currentDep.getSuperiorId().equals(dto.getSuperiorId());
                
                if (departmentChanged) {
                    // 将原部门设为非当前
                    currentDep.setIsCurrent(0);
                    employeeDepartmentMapper.updateById(currentDep);

                    // 添加新部门记录
                    EmployeeDepartment newDep = dto.toEmployeeDepartment();
                    newDep.setEmpId(dto.getId());
                    newDep.setIsCurrent(1);
                    
                    int depResult = employeeDepartmentMapper.insert(newDep);
                    if (depResult <= 0) {
                        throw new RuntimeException("部门信息更新失败");
                    }
                }
                // 如果部门信息没有变化，则不需要更新
            } else {
                // 如果没有当前部门，直接添加新记录
                EmployeeDepartment newDep = dto.toEmployeeDepartment();
                newDep.setEmpId(dto.getId());
                newDep.setIsCurrent(1);
                
                int depResult = employeeDepartmentMapper.insert(newDep);
                if (depResult <= 0) {
                    throw new RuntimeException("部门信息更新失败");
                }
            }
            
            return 1;
        } catch (Exception e) {
            log.error("更新员工及部门信息失败: {}", e.getMessage());
            throw new RuntimeException("更新员工及部门信息失败: " + e.getMessage());
        }
    }
}